#include "wxsmith.h"
#include "wxsproject.h"
#include "wxsmithmime.h"
#include "wxssettings.h"
#include "wxsextresmanager.h"
#include "wxsresourcefactory.h"
#include "properties/wxsproperties.h"
#include <prep.h>
#include <M_Code_auibook.h>
#include <projectloader_hooks.h>
#include <manager.h>
#include <configmanager.h>
#include <projectmanager.h>
#include <logmanager.h>
#include <sqplus.h>
#include <sc_base_types.h>
#include <wx/xrc/xmlres.h>

namespace {
  const int idConfigureWxSmith = XRCID( "idConfigureWxSmith" );
  const int idViewWxSmith = wxNewId();  //切换显示wxSmith资源和属性浏览器
  const int idViewWxSmithResource = wxNewId();  //切换显示wxSmith资源浏览器
  const int idViewWxSmithProperty = wxNewId();  //切换显示wxSmith属性浏览器
  static const char * Events_xpm[] = {
    "16 16 2 1",
    "     c None",
    ".    c #000000",
    "                ",
    "    ..    ..    ",
    "   .        .   ",
    "   .        .   ",
    "   .        .   ",
    "   .        .   ",
    "   .        .   ",
    " ..          .. ",
    "   .        .   ",
    "   .        .   ",
    "   .        .   ",
    "   .        .   ",
    "   .        .   ",
    "    ..    ..    ",
    "                ",
    "                "
  };

  const int placementManagementPane = 0;
  const int placementOnePane = 1;
  const int placementTwoPanes = 2;

  inline int GetBrowserPlacements() { return Manager::Get()->GetConfigManager( _T( "wxsmith" ) )->ReadInt( _T( "/browserplacements" ), 0 ); }
}

wxSmith* wxSmith::m_Singleton = 0;

BEGIN_EVENT_TABLE( wxSmith, M_Code_Plugin )
  EVT_UPDATE_UI( idViewWxSmith, wxSmith::OnUpdateUI )
  EVT_UPDATE_UI( idViewWxSmithResource, wxSmith::OnUpdateUI )
  EVT_UPDATE_UI( idViewWxSmithProperty, wxSmith::OnUpdateUI )
  EVT_MENU( idConfigureWxSmith, wxSmith::OnConfigure )
  EVT_MENU( idViewWxSmith, wxSmith::OnViewBrowsers )
  EVT_MENU( idViewWxSmithResource, wxSmith::OnViewResourceBrowser )
  EVT_MENU( idViewWxSmithProperty, wxSmith::OnViewPropertyBrowser )
  EVT_MENU( -1, wxSmith::OnMenu )
END_EVENT_TABLE()

wxSmith::wxSmith() {
}

wxSmith::~wxSmith() {
}

void wxSmith::OnAttach() {
  wxASSERT( m_Singleton == 0 );
  BuildBrowsers();
  ProjectLoaderHooks::HookFunctorBase* wxSmithHook = new ProjectLoaderHooks::HookFunctor<wxSmith>( this, &wxSmith::OnProjectHook );
  m_HookId = ProjectLoaderHooks::RegisterHook( wxSmithHook );
  m_Singleton = this;
  wxsResourceFactory::OnAttachAll();
  Manager::Get()->RegisterEventSink( cbEVT_PROJECT_OPEN, new cbEventFunctor<wxSmith, CodeBlocksEvent>( this, &wxSmith::OnProjectOpened ) );
  Manager::Get()->RegisterEventSink( cbEVT_PROJECT_CLOSE, new cbEventFunctor<wxSmith, CodeBlocksEvent>( this, &wxSmith::OnProjectClose ) );
  Manager::Get()->RegisterEventSink( cbEVT_PROJECT_RENAMED, new cbEventFunctor<wxSmith, CodeBlocksEvent>( this, &wxSmith::OnProjectRenamed ) );
  RegisterScripting();
}

void wxSmith::BuildBrowserParents() {
  m_Splitter = 0;
  m_ResourceBrowserParent = 0;
  m_PropertyBrowserParent = 0;
  switch( GetBrowserPlacements() ) {
    case placementOnePane: {
      m_Splitter = new wxsStoringSplitterWindow( Manager::Get()->GetAppWindow() );
      m_ResourceBrowserParent = new wxPanel( m_Splitter->GetSplitter(), -1, wxDefaultPosition, wxDefaultSize, 0 );
      m_PropertyBrowserParent = new wxPanel( m_Splitter->GetSplitter(), -1, wxDefaultPosition, wxDefaultSize, 0 );
      m_Splitter->Split( m_ResourceBrowserParent, m_PropertyBrowserParent );
      m_Splitter->SetSize( 150, 450 );
      CodeBlocksDockEvent evt( cbEVT_ADD_DOCK_WINDOW );
      evt.name = _T( "wxSmithOnePane" );
      evt.title = _T( "wxSmith" );
      evt.pWindow = m_Splitter;
      evt.dockSide = CodeBlocksDockEvent::dsFloating;
      evt.desiredSize.Set( 150, 450 );
      evt.floatingSize.Set( 150, 450 );
      evt.minimumSize.Set( 50, 50 );
      Manager::Get()->ProcessEvent( evt );
      break;
    }
    case placementTwoPanes: {
      m_ResourceBrowserParent = new wxPanel( Manager::Get()->GetAppWindow(), -1, wxDefaultPosition, wxDefaultSize, 0 );
      m_PropertyBrowserParent = new wxPanel( Manager::Get()->GetAppWindow(), -1, wxDefaultPosition, wxDefaultSize, 0 );
      CodeBlocksDockEvent evt( cbEVT_ADD_DOCK_WINDOW );
      evt.name = _T( "wxSmithTwoPanes_ResourceBrowser" );
      evt.title = _T( "wxSmith - Resource Browser" );
      evt.pWindow = m_ResourceBrowserParent;
      evt.dockSide = CodeBlocksDockEvent::dsFloating;
      evt.desiredSize.Set( 150, 450 );
      evt.floatingSize.Set( 150, 450 );
      evt.minimumSize.Set( 50, 50 );
      Manager::Get()->ProcessEvent( evt );
      evt.name = _T( "wxSmithTwoPanes_PropertyBrowser" );
      evt.title = _T( "wxSmith - Property Browser" );
      evt.pWindow = m_PropertyBrowserParent;
      Manager::Get()->ProcessEvent( evt );
      break;
    }
    default: {
      M_Code_AuiNotebook* Notebook = Manager::Get()->GetProjectManager()->GetUI().GetNotebook();
      wxASSERT( Notebook != 0 );
      m_Splitter = new wxsStoringSplitterWindow( Notebook );
      Notebook->AddPage( m_Splitter, _T( "资源" ) );
      m_ResourceBrowserParent = new wxPanel( m_Splitter->GetSplitter(), -1, wxDefaultPosition, wxDefaultSize, 0 );
      m_PropertyBrowserParent = new wxPanel( m_Splitter->GetSplitter(), -1, wxDefaultPosition, wxDefaultSize, 0 );
      m_Splitter->Split( m_ResourceBrowserParent, m_PropertyBrowserParent );
    }
  }
}


void wxSmith::BuildBrowsers() {
  BuildBrowserParents();
  wxSizer* Sizer = new wxGridSizer( 1 );
  wxTreeCtrl* ResourceBrowser = new wxsResourceTree( m_ResourceBrowserParent );
  Sizer->Add( ResourceBrowser, 1, wxGROW | wxALL );
  m_ResourceBrowserParent->SetSizer( Sizer );
  Sizer = new wxGridSizer( 1 );
  wxsPropertyGridManager* PGManager = new wxsPropertyGridManager( m_PropertyBrowserParent, -1, wxDefaultPosition, wxDefaultSize, wxPG_TOOLBAR | wxTAB_TRAVERSAL | wxPG_SPLITTER_AUTO_CENTER );
  PGManager->AddPage( _T( "Properties" ) );
  PGManager->AddPage( _T( "Events" ), wxBitmap( Events_xpm ) );
  PGManager->SelectPage( 0 );
  Sizer->Add( PGManager, 1, wxGROW );
  m_PropertyBrowserParent->SetSizer( Sizer );
}

void wxSmith::OnRelease( M_Code_unused bool appShutDown ) {
  UnregisterScripting();
  ProjectLoaderHooks::UnregisterHook( m_HookId, true );
  for( ProjectMapI i = m_ProjectMap.begin(); i != m_ProjectMap.end(); ++i ) {
    if( i->second ) {
      delete i->second;
      i->second = 0;
    }
  }
  wxsExtResManager::Get()->DeleteAll();
  m_ProjectMap.clear();
  wxsResourceFactory::OnReleaseAll();
  if( m_Singleton == this ) {
    m_Singleton = 0;
  }
}

cbConfigurationPanel* wxSmith::GetConfigurationPanel( wxWindow* parent ) {
  return new wxsSettings( parent );
}

cbConfigurationPanel* wxSmith::GetProjectConfigurationPanel( wxWindow* parent, M_Code_Project* project ) {
  ProjectMapI i = m_ProjectMap.find( project );
  if( i == m_ProjectMap.end() ) {
    return 0;
  }
  return i->second->GetProjectConfigurationPanel( parent );
}

void wxSmith::BuildModuleMenu( M_Code_unused const ModuleType type, M_Code_unused wxMenu* menu, const FileTreeData* ) {
}

bool wxSmith::BuildToolBar( M_Code_unused wxToolBar* toolBar ) {
  return false;
}

void wxSmith::OnProjectHook( M_Code_Project* project, TiXmlElement* elem, bool loading ) {
  assert( project );
  wxsProject* Proj = GetSmithProject( project );
  assert( Proj );
  if( loading ) {
    Proj->ReadConfiguration( elem );
  } else {
    Proj->WriteConfiguration( elem );
  }
}

void wxSmith::OnProjectOpened( CodeBlocksEvent& event ) {
  M_Code_Project* Proj = event.GetProject();
  wxsProject* wxsProj = GetSmithProject( Proj );
  wxsProj->UpdateName();
  Proj->SetModified( wxsProj->GetWasModifiedDuringLoad() );
  event.Skip();
}

void wxSmith::OnProjectClose( CodeBlocksEvent& event ) {
  M_Code_Project* Proj = event.GetProject();
  ProjectMapI i = m_ProjectMap.find( Proj );
  if( i == m_ProjectMap.end() ) {
    return;
  }
  delete i->second;
  m_ProjectMap.erase( i );
  event.Skip();
}

void wxSmith::OnProjectRenamed( M_Code_unused CodeBlocksEvent& event ) {
  M_Code_Project* Proj = event.GetProject();
  ProjectMapI i = m_ProjectMap.find( Proj );
  if( i == m_ProjectMap.end() ) {
    return;
  }
  i->second->UpdateName();
  event.Skip();
}

void wxSmith::OnConfigure( M_Code_unused wxCommandEvent& event ) {
  M_Code_Project* Proj = Manager::Get()->GetProjectManager()->GetActiveProject();
  if( Proj ) {
    GetSmithProject( Proj )->Configure();
  }
}

void wxSmith::OnMenu( wxCommandEvent& event ) {
  M_Code_Project* Proj = Manager::Get()->GetProjectManager()->GetActiveProject();
  if( Proj ) {
    if( wxsResourceFactory::NewResourceMenu( event.GetId(), GetSmithProject( Proj ) ) ) {
      return;
    }
  }
  event.Skip();
}

void wxSmith::OnViewBrowsers( wxCommandEvent& event ) {
  CodeBlocksDockEvent evt( event.IsChecked() ? cbEVT_SHOW_DOCK_WINDOW : cbEVT_HIDE_DOCK_WINDOW );
  evt.pWindow = m_Splitter;
  Manager::Get()->ProcessEvent( evt );
}

void wxSmith::OnViewPropertyBrowser( wxCommandEvent& event ) {
  CodeBlocksDockEvent evt( event.IsChecked() ? cbEVT_SHOW_DOCK_WINDOW : cbEVT_HIDE_DOCK_WINDOW );
  evt.pWindow = m_PropertyBrowserParent;
  Manager::Get()->ProcessEvent( evt );
}

void wxSmith::OnViewResourceBrowser( M_Code_unused wxCommandEvent& event ) {
  CodeBlocksDockEvent evt( event.IsChecked() ? cbEVT_SHOW_DOCK_WINDOW : cbEVT_HIDE_DOCK_WINDOW );
  evt.pWindow = m_ResourceBrowserParent;
  Manager::Get()->ProcessEvent( evt );
}

void wxSmith::OnUpdateUI( M_Code_unused wxUpdateUIEvent& event ) {
  wxMenuBar* Bar = Manager::Get()->GetAppFrame()->GetMenuBar();
  Bar->Check( idViewWxSmith, IsWindowReallyShown( m_Splitter ) );
  Bar->Check( idViewWxSmithResource, IsWindowReallyShown( m_ResourceBrowserParent ) );
  Bar->Check( idViewWxSmithProperty, IsWindowReallyShown( m_PropertyBrowserParent ) );
}

M_Code_Project* wxSmith::GetM_Code_Project( wxsProject* Proj ) {
  return Proj->GetM_Code_Project();
}

wxsProject* wxSmith::GetSmithProject( M_Code_Project* Proj ) {
  assert( Proj );
  ProjectMapI i = m_ProjectMap.find( Proj );
  if( i == m_ProjectMap.end() ) {
    wxsProject* NewProj = new wxsProject( Proj );
    m_ProjectMap[Proj] = NewProj;
    return NewProj;
  }
  return i->second;
}

void wxSmith::ShowResourcesTab() {
  M_Code_AuiNotebook* Notebook = Manager::Get()->GetProjectManager()->GetUI().GetNotebook();
  Notebook->SetSelection( Notebook->GetPageIndex( m_Splitter ) );
}

void wxSmith::RegisterScripting() {
  Manager::Get()->GetScriptingManager();
  if( SquirrelVM::GetVMPtr() ) {
    SqPlus::RegisterGlobal( &wxSmith::RecoverWxsFile, "WxsRecoverWxsFile" );
  }
}

void wxSmith::UnregisterScripting() {
  Manager::Get()->GetScriptingManager();
  HSQUIRRELVM v = SquirrelVM::GetVMPtr();
  if( v ) {
    sq_pushroottable( v );
    sq_pushstring( v, "WxsRecoverWxsFile", -1 );
    sq_deleteslot( v, -2, false );
    sq_poptop( v );
  }
}

bool wxSmith::RecoverWxsFile( const wxString& WxsResourceSettings ) {
  wxSmith* This = wxSmith::Get();
  if( !This ) {
    return false;
  }
  if( !ProjectManager::Get()->GetActiveProject() ) {
    return false;
  }
  wxsProject* project = This->GetSmithProject( ProjectManager::Get()->GetActiveProject() );
  if( !project ) {
    return false;
  }
  return project->RecoverWxsFile( WxsResourceSettings );
}
